namespace SimpleWebServices.Configuration
{
    using System;
    using System.IO;
    using System.Web;
    using System.Xml;
    using System.Xml.XPath;
    using Moq;
    using SimpleWebServices;
    using SimpleWebServices.Web;
    using Xunit;

    public sealed class FileSettingFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<FileSetting>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("file")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            FileSetting actual = "<file cache-condition='last-modified' duration='P1Y' cache-control='Public' content-type='text/plain' location='~/Content/example.txt' path='/example.txt' />".Deserialize<FileSetting>();

            Assert.Equal<string>("last-modified", actual.CacheCondition);
            Assert.Equal<string>("Public", actual.CacheControl);
            Assert.Equal<string>("text/plain", actual.ContentType);
            Assert.Equal<string>("P1Y", actual.DurationValue);
            Assert.Equal<string>("~/Content/example.txt", actual.Location);
            Assert.Equal<string>("/example.txt", actual.Path);
        }

        [Fact]
        public void deserializeEmpty()
        {
            FileSetting actual = "<file />".Deserialize<FileSetting>();

            Assert.Null(actual.CacheCondition);
            Assert.Null(actual.CacheControl);
            Assert.Null(actual.ContentType);
            Assert.Null(actual.Location);
            Assert.Null(actual.Path);
        }

        [Fact]
        public void serialize()
        {
            FileSetting obj = new FileSetting
            {
                CacheCondition = "Expires",
                CacheControl = "Public",
                ContentType = "text/plain",
                DurationValue = "P1Y",
                Location = "~/Content/example.txt",
                Path = "/example.txt"
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/file[@cache-condition='Expires'][@duration='P1Y'][@cache-control='Public'][@content-type='text/plain'][@location='~/Content/example.txt'][@path='/example.txt'])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new FileSetting());
        }

        [Fact]
        public void prop_CacheCondition()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("CacheCondition"))
                .XmlAttribute("cache-condition")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_CacheControl()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("CacheControl"))
                .XmlAttribute("cache-control")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_ContentType()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("ContentType"))
                .XmlAttribute("content-type")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Duration()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("Duration"))
                .XmlIgnore()
                .TypeIs<TimeSpan>()
                .Result);
        }

        [Fact]
        public void prop_Duration_get()
        {
            FileSetting obj = new FileSetting
            {
                DurationValue = "P1Y"
            };

            TimeSpan expected = XmlConvert.ToTimeSpan(obj.DurationValue);
            TimeSpan actual = obj.Duration;

            Assert.Equal<TimeSpan>(expected, actual);
        }

        [Fact]
        public void prop_DurationValue()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("DurationValue"))
                .XmlAttribute("duration")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Location()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("Location"))
                .XmlAttribute("location")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Path()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("Path"))
                .XmlAttribute("path")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Cacheability()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("Cacheability"))
                .XmlIgnore()
                .TypeIs<HttpCacheability>()
                .DefaultValueIs(HttpCacheability.NoCache)
                .Result);
        }

        [Fact]
        public void prop_Cacheability_whenCacheControlIsPrivate()
        {
            FileSetting obj = new FileSetting
            {
                CacheControl = "private"
            };

            Assert.Equal<HttpCacheability>(HttpCacheability.Private, obj.Cacheability);
        }

        [Fact]
        public void prop_Cacheability_whenCacheControlIsPublic()
        {
            FileSetting obj = new FileSetting
            {
                CacheControl = "public"
            };

            Assert.Equal<HttpCacheability>(HttpCacheability.Public, obj.Cacheability);
        }

        [Fact]
        public void prop_Cacheability_whenCacheControlIsServer()
        {
            FileSetting obj = new FileSetting
            {
                CacheControl = "server"
            };

            Assert.Equal<HttpCacheability>(HttpCacheability.Server, obj.Cacheability);
        }

        [Fact]
        public void prop_File()
        {
            Assert.True(new PropertyExpectations(typeof(FileSetting).GetProperty("File"))
                .XmlIgnore()
                .TypeIs<FileInfo>()
                .DefaultValueIsNull()
                .Result);
        }

        [Fact]
        public void prop_File_whenLocationIsNull()
        {
            FileSetting obj = new FileSetting
            {
                Location = null
            };

            Assert.Null(obj.File);
        }

        [Fact]
        public void prop_File_whenLocationIsEmpty()
        {
            FileSetting obj = new FileSetting
            {
                Location = string.Empty
            };

            Assert.Null(obj.File);
        }

        [Fact]
        public void prop_File_whenLocationIsUncPath()
        {
            FileSetting obj = new FileSetting
            {
                Location = @"\\unc\example.txt"
            };

            Assert.Equal<string>(@"\\unc\example.txt", obj.File.FullName);
        }

        [Fact]
        public void prop_File_whenLocationIsDrivePath()
        {
            FileSetting obj = new FileSetting
            {
                Location = @"C:\example.txt"
            };

            Assert.Equal<string>(@"C:\example.txt", obj.File.FullName);
        }

        [Fact]
        public void prop_File_whenLocationIsVirtualPath()
        {
            try
            {
                var mock = new Mock<HttpContextBase>();
                mock.Setup<string>(x => x.Request.MapPath(It.Is<string>(virtualPath => virtualPath == "~/example.txt"))).Returns(@"C:\inetpub\wwwroot\application\example.txt").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                FileSetting obj = new FileSetting
                {
                    Location = "~/example.txt"
                };

                Assert.Equal<string>(@"C:\inetpub\wwwroot\application\example.txt", obj.File.FullName);

                mock.VerifyAll();
            }
            finally
            {
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void prop_File_whenLocationIsRelativePath()
        {
            try
            {
                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.PhysicalApplicationPath).Returns(@"C:\inetpub\wwwroot\application").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                FileSetting obj = new FileSetting
                {
                    Location = "example.txt"
                };

                Assert.Equal<string>(@"C:\inetpub\wwwroot\application\example.txt", obj.File.FullName);

                mock.VerifyAll();
            }
            finally
            {
                HttpContextFactory.Reset();
            }
        }
    }
}